"""
YAML配置文件解析器

解析OpenBMC中的YAML接口定义文件
"""

import os
import yaml
import logging
from pathlib import Path
from typing import List, Dict, Any, Optional
from data_structures import (
    DBusInterface, DBusMethod, DBusProperty, DBusSignal, 
    Parameter, AccessType, ParameterDirection
)


class YAMLParser:
    """YAML接口定义文件解析器"""
    
    def __init__(self):
        """初始化解析器"""
        self.logger = logging.getLogger(__name__)
        self.type_mapping = {
            # YAML类型到D-Bus类型签名的映射
            'byte': 'y',
            'boolean': 'b', 
            'int16': 'n',
            'uint16': 'q',
            'int32': 'i',
            'uint32': 'u',
            'int64': 'x',
            'uint64': 't',
            'double': 'd',
            'string': 's',
            'object_path': 'o',
            'signature': 'g',
            'variant': 'v',
            'array': 'a',
            'struct': '(',
            'dict_entry': '{',
        }
    
    def parse_interface_yaml(self, yaml_file_path: str) -> Optional[DBusInterface]:
        """
        解析单个YAML接口文件
        
        Args:
            yaml_file_path: YAML文件路径
            
        Returns:
            解析得到的DBusInterface对象，失败时返回None
        """
        try:
            with open(yaml_file_path, 'r', encoding='utf-8') as f:
                data = yaml.safe_load(f)
                
            if not data:
                self.logger.warning(f"空的YAML文件: {yaml_file_path}")
                return None
                
            return self._parse_interface_data(data, yaml_file_path)
            
        except FileNotFoundError:
            self.logger.error(f"YAML文件不存在: {yaml_file_path}")
            return None
        except yaml.YAMLError as e:
            self.logger.error(f"YAML解析错误 {yaml_file_path}: {e}")
            return None
        except Exception as e:
            self.logger.error(f"解析YAML文件时发生未知错误 {yaml_file_path}: {e}")
            return None
    
    def scan_yaml_directory(self, yaml_dir: str) -> List[DBusInterface]:
        """
        扫描目录下的所有YAML接口文件
        
        Args:
            yaml_dir: YAML文件目录路径
            
        Returns:
            解析得到的DBusInterface对象列表
        """
        interfaces = []
        yaml_path = Path(yaml_dir)
        
        if not yaml_path.exists():
            self.logger.error(f"YAML目录不存在: {yaml_dir}")
            return interfaces
        
        # 查找所有interface.yaml文件
        for yaml_file in yaml_path.rglob("*.interface.yaml"):
            self.logger.debug(f"解析YAML文件: {yaml_file}")
            interface = self.parse_interface_yaml(str(yaml_file))
            if interface:
                interfaces.append(interface)
        
        self.logger.info(f"从{yaml_dir}解析到{len(interfaces)}个接口")
        return interfaces
    
    def _parse_interface_data(self, data: Dict[str, Any], source_file: str) -> Optional[DBusInterface]:
        """
        解析YAML数据为DBusInterface对象
        
        Args:
            data: YAML数据字典
            source_file: 源文件路径
            
        Returns:
            DBusInterface对象
        """
        # 从文件路径推断接口名称
        interface_name = self._extract_interface_name_from_path(source_file)
        
        # 创建接口对象
        interface = DBusInterface(
            name=interface_name,
            namespace=self._extract_namespace(interface_name),
            source_file=source_file,
            description=data.get('description', ''),
            category=self._categorize_interface(interface_name)
        )
        
        # 解析方法
        methods = data.get('methods', [])
        if isinstance(methods, list):
            for method_data in methods:
                if isinstance(method_data, dict):
                    method = self._parse_method_from_dict(method_data)
                    if method:
                        interface.methods.append(method)
        
        # 解析属性
        properties = data.get('properties', [])
        if isinstance(properties, list):
            for prop_data in properties:
                if isinstance(prop_data, dict):
                    prop = self._parse_property_from_dict(prop_data)
                    if prop:
                        interface.properties.append(prop)
        
        # 解析信号
        signals = data.get('signals', [])
        if isinstance(signals, list):
            for signal_data in signals:
                if isinstance(signal_data, dict):
                    signal = self._parse_signal_from_dict(signal_data)
                    if signal:
                        interface.signals.append(signal)
        
        # 判断是否为公共接口
        interface.is_public = self._is_public_interface(interface_name)
        
        return interface
    
    def _extract_interface_name_from_path(self, file_path: str) -> str:
        """
        从文件路径提取接口名称
        
        Args:
            file_path: 文件路径
            
        Returns:
            接口名称
        """
        path = Path(file_path)
        
        # 移除.interface.yaml后缀
        name_parts = []
        
        # 从yaml/目录开始构建接口名称
        parts = path.parts
        yaml_index = -1
        for i, part in enumerate(parts):
            if part == 'yaml':
                yaml_index = i
                break
        
        if yaml_index != -1:
            # 从yaml之后的部分构建名称
            for part in parts[yaml_index + 1:]:
                if part.endswith('.interface.yaml'):
                    part = part[:-15]  # 移除.interface.yaml
                name_parts.append(part)
            
            return '.'.join(name_parts)
        
        # 如果找不到yaml目录，直接用文件名
        return path.stem.replace('.interface', '')
    
    def _extract_namespace(self, interface_name: str) -> str:
        """
        提取接口的命名空间
        
        Args:
            interface_name: 接口名称
            
        Returns:
            命名空间
        """
        parts = interface_name.split('.')
        if len(parts) >= 2:
            return '.'.join(parts[:2])
        return parts[0] if parts else ""
    
    def _categorize_interface(self, interface_name: str) -> str:
        """
        对接口进行分类
        
        Args:
            interface_name: 接口名称
            
        Returns:
            接口分类
        """
        name_lower = interface_name.lower()
        
        if 'sensor' in name_lower:
            return "传感器"
        elif 'control' in name_lower or 'power' in name_lower:
            return "控制"
        elif 'log' in name_lower or 'event' in name_lower:
            return "日志"
        elif 'inventory' in name_lower or 'item' in name_lower:
            return "清单"
        elif 'user' in name_lower or 'account' in name_lower:
            return "用户管理"
        elif 'network' in name_lower:
            return "网络"
        elif 'time' in name_lower:
            return "时间"
        elif 'bios' in name_lower:
            return "BIOS"
        elif 'configuration' in name_lower:
            return "配置"
        elif 'association' in name_lower:
            return "关联"
        else:
            return "其他"
    
    def _is_public_interface(self, interface_name: str) -> bool:
        """
        判断是否为公共接口
        
        Args:
            interface_name: 接口名称
            
        Returns:
            是否为公共接口
        """
        # xyz.openbmc_project开头的都是公共接口
        if interface_name.startswith('xyz.openbmc_project'):
            return True
        
        # 排除厂商特定的接口
        vendor_keywords = [
            'intel', 'ibm', 'facebook', 'microsoft', 'google',
            'ampere', 'nvidia', 'amd', 'qualcomm', 'broadcom'
        ]
        
        name_lower = interface_name.lower()
        for keyword in vendor_keywords:
            if keyword in name_lower:
                return False
        
        return True
    
    def _parse_method_from_dict(self, method_data: Dict[str, Any]) -> Optional[DBusMethod]:
        """
        从字典解析方法定义
        
        Args:
            method_data: 方法数据字典
            
        Returns:
            DBusMethod对象
        """
        method_name = method_data.get('name', '')
        if not method_name:
            return None
            
        method = DBusMethod(
            name=method_name,
            description=method_data.get('description', '')
        )
        
        # 解析输入参数
        parameters = method_data.get('parameters', [])
        if isinstance(parameters, list):
            for param_data in parameters:
                if isinstance(param_data, dict):
                    param = self._parse_parameter_from_dict(param_data, ParameterDirection.IN)
                    if param:
                        method.input_params.append(param)
        
        # 解析返回值
        returns = method_data.get('returns', [])
        if isinstance(returns, list):
            for return_data in returns:
                if isinstance(return_data, dict):
                    param = self._parse_parameter_from_dict(return_data, ParameterDirection.OUT)
                    if param:
                        method.output_params.append(param)
        
        # 解析异常
        errors = method_data.get('errors', [])
        if isinstance(errors, list):
            method.exceptions = [str(error) for error in errors]
        
        return method
    
    def _parse_property_from_dict(self, prop_data: Dict[str, Any]) -> Optional[DBusProperty]:
        """
        从字典解析属性定义
        
        Args:
            prop_data: 属性数据字典
            
        Returns:
            DBusProperty对象
        """
        prop_name = prop_data.get('name', '')
        if not prop_name:
            return None
            
        # 解析访问权限 - 默认为readwrite，除非明确指定
        access_str = prop_data.get('access', 'readwrite')
        try:
            access = AccessType(access_str)
        except ValueError:
            access = AccessType.READWRITE
        
        # 解析类型
        type_info = prop_data.get('type', 'string')
        type_signature = self._convert_type_to_signature(type_info)
        
        return DBusProperty(
            name=prop_name,
            type_signature=type_signature,
            access=access,
            description=prop_data.get('description', ''),
            default_value=str(prop_data.get('default', '')),
            units=prop_data.get('units', '')
        )
    
    def _parse_signal_from_dict(self, signal_data: Dict[str, Any]) -> Optional[DBusSignal]:
        """
        从字典解析信号定义
        
        Args:
            signal_data: 信号数据字典
            
        Returns:
            DBusSignal对象
        """
        signal_name = signal_data.get('name', '')
        if not signal_name:
            return None
            
        signal = DBusSignal(
            name=signal_name,
            description=signal_data.get('description', '')
        )
        
        # 解析参数
        parameters = signal_data.get('parameters', [])
        if isinstance(parameters, list):
            for param_data in parameters:
                if isinstance(param_data, dict):
                    param = self._parse_parameter_from_dict(param_data)
                    if param:
                        signal.params.append(param)
        
        return signal
    
    def _parse_parameter_from_dict(self, param_data: Dict[str, Any], 
                                  default_direction: ParameterDirection = ParameterDirection.IN) -> Optional[Parameter]:
        """
        从字典解析参数定义
        
        Args:
            param_data: 参数数据字典
            default_direction: 默认方向
            
        Returns:
            Parameter对象
        """
        if not isinstance(param_data, dict):
            return None
        
        param_name = param_data.get('name', '')
        if not param_name:
            return None
        
        # 解析方向 - 通常输入参数不会明确指定direction
        direction_str = param_data.get('direction', default_direction.value)
        try:
            direction = ParameterDirection(direction_str)
        except ValueError:
            direction = default_direction
        
        # 解析类型
        type_info = param_data.get('type', 'string')
        type_signature = self._convert_type_to_signature(type_info)
        
        return Parameter(
            name=param_name,
            type_signature=type_signature,
            direction=direction,
            description=param_data.get('description', '')
        )
    
    def _convert_type_to_signature(self, type_info: Any) -> str:
        """
        将YAML类型信息转换为D-Bus类型签名
        
        Args:
            type_info: 类型信息
            
        Returns:
            D-Bus类型签名
        """
        if isinstance(type_info, str):
            # 处理简单的字符串类型
            type_str = type_info.lower().strip()
            
            # 处理array[type]格式
            if type_str.startswith('array[') and type_str.endswith(']'):
                element_type_str = type_str[6:-1]  # 去除'array['和']'
                element_type = self._convert_type_to_signature(element_type_str)
                return f'a{element_type}'
            
            # 处理enum[type]格式
            if type_str.startswith('enum[') and type_str.endswith(']'):
                # 枚举通常映射为字符串或整数
                return 's'  # 默认为字符串
            
            # 直接映射
            return self.type_mapping.get(type_str, 's')
            
        elif isinstance(type_info, dict):
            # 处理复合类型
            if 'array' in type_info:
                element_type = self._convert_type_to_signature(type_info['array'])
                return f'a{element_type}'
            elif 'struct' in type_info:
                struct_types = []
                for field in type_info['struct']:
                    struct_types.append(self._convert_type_to_signature(field))
                return f"({''.join(struct_types)})"
            elif 'dict' in type_info:
                key_type = self._convert_type_to_signature(type_info['dict'].get('key', 'string'))
                value_type = self._convert_type_to_signature(type_info['dict'].get('value', 'variant'))
                return f'a{{{key_type}{value_type}}}'
        
        # 默认返回字符串类型
        return 's'
